#pragma once

#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>

// 有效载荷长度(int)\r\n
// 协议编号(int)\r\n
// jsonstr\r\n -- request or response

// 如果我未来cs同时存在10几种协议呢？？

// class Login
// {

// };
// class Register
// {

// };
// class Message
// {

// };

class Request
{
public:
    Request()
    {
        _x = _y = _oper = 0;
    }
    // 序列号对象
    bool Serialize(std::string *out)
    {
        // 1. 手写 "_x" "_oper" "_y" --- 字符串拼接转换
        // 2. 现成工具

        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;

        Json::StyledWriter writer;
        *out = writer.write(root);
        if (out->empty())
            return false;
        return true;
    }

    // 反序列化对象
    bool Deserialize(std::string &in)
    {
        Json::Reader reader;
        Json::Value root;
        bool ret = reader.parse(in, root);
        if (!ret)
            return false;

        _x = root["x"].asInt();
        _y = root["y"].asInt();
        _oper = root["oper"].asInt();

        return true;
    }
    int X()
    {
        return _x;
    }
    int Y()
    {
        return _y;
    }
    char Oper()
    {
        return _oper;
    }
    ~Request()
    {
    }

    // private:
public: // 加快速度
    // x oper y -- 约定1
    int _x;
    int _y;
    char _oper;
};

class Response
{
public:
    Response() : _result(0), _code(0)
    {
    }
    // 序列号对象
    bool Serialize(std::string *out)
    {
        // 1. 手写 "_x" "_oper" "_y" --- 字符串拼接转换
        // 2. 现成工具

        // 用这个设置
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;

        Json::StyledWriter writer;
        // 以什么样的方式写入
        *out = writer.write(root);
        if (out->empty())
            return false;
        return true;
    }

    // 反序列化对象
    bool Deserialize(std::string &in)
    {
        Json::Reader reader;
        Json::Value root;
        bool ret = reader.parse(in, root);
        if (!ret)
            return false;

        _result = root["result"].asInt();
        _code = root["code"].asInt();

        return true;
    }
    void SetResult(int r)
    {
        _result = r;
    }
    void SetCode(int c)
    {
        _code = c;
    }
    void Print()
    {
        std::cout << _result << "[" << _code << "]" << std::endl;
    }
    ~Response()
    {
    }

private:
    int _result; //
    int _code;   // 可信度
};

static const std::string sep = "\r\n";

class Protocol
{
public:
    static std::string Package(const std::string &jsonstr)
    {
        // jsonstr -> len\r\njsonstr\r\n
        if (jsonstr.empty())
            return std::string();
        std::string json_length = std::to_string(jsonstr.size());
        return json_length + sep + jsonstr + sep;
    }
    static bool DigitSafeCheck(const std::string str)
    {
        for (int i = 0; i < str.size(); i++)
        {
            if (!(str[i] >= '0' && str[i] <= '9'))
                return false;
        }
        return true;
    }

    // len\r\njsonstr\r\n
    // len\r\njsonstr\r\nlen\r\njsonstr\r\n
    // len\r\njsonstr\r\nlen\r
    // len\r\n
    // len\r\njs
    // len\r
    // len
    // origin_str: 从网络中读取上来的字符串,输入输出
    // package: 输出参数，如果有完整的json报文，就返回
    static int Unpack(std::string &origin_str, std::string *package)
    {
        if (!package)
            return 0;
        auto pos = origin_str.find(sep); // 从左向右
        if (pos == std::string::npos)
            return 0;
        // 至少说明，我们收到了一个报文的长度
        std::string len_str = origin_str.substr(0, pos);
        if (!DigitSafeCheck(len_str))
        {
            return -1;
        }
        int digit_len = std::stoi(len_str);
        // 如果我得到了当前报文的长度
        // 根据协议，我可以推测出，一个完整报文的长度是多少
        int target_len = len_str.size() + digit_len + 2 * sep.size();
        if (origin_str.size() < target_len)
            return 0;

        ///////////////上面的逻辑，我们对origin_string都没做/////////////////
        // 我保证，origin_str内部，一定有一个完整的报文请求！
        *package = origin_str.substr(pos + sep.size(), digit_len);
        origin_str.erase(0, target_len);
        return package->size();
    }
};